package com.example.grpc.consume.service.impl;

import com.example.grpc.consume.model.dto.CompanyDto;
import com.example.grpc.consume.model.dto.UserDto;
import com.example.grpc.consume.service.UserService;
import com.example.grpc.remote.RApiCompany;
import com.example.grpc.remote.RApiUser;
import com.example.grpc.remote.RApiUserRegisterRequest;
import com.example.grpc.remote.RApiUserRegisterResponse;
import com.example.grpc.remote.UserServiceGrpc;
import io.grpc.stub.StreamObserver;
import net.devh.boot.grpc.client.inject.GrpcClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

/**
 * @author liyuncong
 * @version 1.0
 * @file UserServiceImpl
 * @brief UserServiceImpl
 * @details UserServiceImpl
 * @date 2022-11-20
 *
 * Edit History
 * ----------------------------------------------------------------------------
 * DATE                     NAME               DESCRIPTION
 * 2022-11-20               liyuncong          Created
 */
@Service
public class UserServiceImpl implements UserService {

    private static final Logger logger = LoggerFactory.getLogger(UserServiceImpl.class);

    @GrpcClient(value = "GLOBAL")
    private UserServiceGrpc.UserServiceBlockingStub userServiceBlockingStub;
    @GrpcClient(value = "GLOBAL")
    private UserServiceGrpc.UserServiceStub userServiceStub;

    @Override
    public List<UserDto> findAllByCompany(CompanyDto companyDto) {
        final RApiCompany rApiCompany = RApiCompany.newBuilder()
            .setCompanyId(companyDto.getCompanyId())
            .setCompanyName(companyDto.getCompanyName())
            .build();
        final Iterator<RApiUser> rApiUserIterator = userServiceBlockingStub.searchUsersByCompany(rApiCompany);
        List<UserDto> result = new ArrayList<>();
        while (rApiUserIterator.hasNext()) {
            final RApiUser rApiUser = rApiUserIterator.next();
            final UserDto userDto = new UserDto();
            BeanUtils.copyProperties(rApiUser, userDto);
            result.add(userDto);
        }
        return result;
    }

    @Override
    public Boolean register(CompanyDto companyDto, List<UserDto> userDtos) {
        final RApiCompany rApiCompany = RApiCompany.newBuilder()
            .setCompanyId(companyDto.getCompanyId())
            .setCompanyName(companyDto.getCompanyName())
            .build();
        List<RApiUser> apiUsers = new ArrayList<>(userDtos.size());
        RApiUser.Builder builder = RApiUser.newBuilder();
        userDtos.forEach(userDto -> {
            apiUsers.add(builder.setUserId(userDto.getUserId())
                .setUsername(userDto.getUsername())
                .setFullName(userDto.getFullName())
                .build());
        });
        final RApiUserRegisterRequest rApiUserRegisterRequest = RApiUserRegisterRequest
            .newBuilder()
            .setRApiCompany(rApiCompany)
            .addAllRApiUser(apiUsers)
            .build();
        final RApiUserRegisterResponse registerResponse = userServiceBlockingStub.register(rApiUserRegisterRequest);
        return registerResponse.getResult();
    }

    @Override
    public List<UserDto> findAllUsers() {

        final CountDownLatch countDownLatch = new CountDownLatch(1);
        List<UserDto> users = new ArrayList<>();

        final StreamObserver<RApiUser> rApiUserStreamObserver = new StreamObserver<>() {

            @Override
            public void onNext(RApiUser rApiUser) {
                final UserDto userDto = new UserDto();
                BeanUtils.copyProperties(rApiUser, userDto);
                users.add(userDto);
            }

            @Override
            public void onError(Throwable throwable) {

            }

            @Override
            public void onCompleted() {
                countDownLatch.countDown();
            }
        };

        final StreamObserver<RApiCompany> rApiCompanyStreamObserver = userServiceStub.searchUsersByCompanies(rApiUserStreamObserver);
        final RApiCompany.Builder builder = RApiCompany.newBuilder();
        for (int i = 0; i < 10; i++) {
            rApiCompanyStreamObserver.onNext(builder
                .setCompanyId(i)
                .setCompanyName("company_" + i)
                .build());
        }
        rApiCompanyStreamObserver.onCompleted();

        try {
            final boolean await = countDownLatch.await(2, TimeUnit.SECONDS);
            if (!await) {
                logger.error("------");
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return users;
    }
}
